package com.zz.springboot.util;

import com.zz.springboot.constant.TypeConstants;
import com.zz.springboot.dto.DataDTO;
import com.zz.springboot.resp.enums.RespCodeEnum;
import com.zz.springboot.exception.BizException;
import com.zz.springboot.initializer.DataInitializer;
import com.zz.springboot.processor.bag.BagDataProcessor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 数据处理工具类（已弃用）
 */
@Slf4j
@Deprecated
public class DataDealUtils2 {

    /**
     * 解析原始数据入口方法
     *
     * @param originData
     * @desc 将原始String数据 -> List<String>
     */
    public static List<String> parseData(String originData) {
        List<String> dataList = new ArrayList<>();  //这里一定不能写成全局的

        /** ------------ 1.中文字符处理 ------------ **/
        //1.1 处理汉字数字，如将“1/2/3各五”转为“1/2/3各5”
        String data = ChineseNumberConverter.convertChineseNumbersToArabic(originData);
        //1.2 处理金额单位及其它字符：元、块、快、米、澳、奥、们、门、香、港
        data = data.replace("元", "").replace("块", "").replace("快", "").replace("米", "").
                replace("奥", "").replace("澳", "").replace("们", "").replace("门", "").
                replace("香", "").replace("港", "");

        /** ------------ 2.数据格式分类处理 ------------ **/
        if (data.contains("各") && !data.contains("包") || data.contains("(") || data.contains("（")) {
            /** 2.1 多个号子同一金额。tips：关键词中带“各”字（注意：这种格式要单独输入，不能和2.2一起输入）**/
            // 如：“1/3/5各20米”或“1\3\5各20米”或“1,3,5各20米”或“1.3.5各20米”或“1、3、5各20米”或“1 3 5各20米”格式，表示1、3、5号各20块
            multiToOne(data, dataList);
        } else if (data.contains("包")) {
            /** 2.2 包双/单 、包双肖 **/
            bag(data, dataList);
        } else {
            /** 2.3 单个号子单个金额 **/
            oneToOne(data, dataList);
        }
        return dataList;
    }

    /**
     * 将原始数据封装为实体类
     *
     * @param dataList
     * @return
     */
    public static List<DataDTO> listToModel(List<String> dataList) {
        List<DataDTO> dataDtos = new ArrayList<>();
        for (int i = 0; i < dataList.size(); i++) {
            String[] metaArr = dataList.get(i).split(":");

            DataDTO dataDTO = new DataDTO();
            int num = Integer.valueOf(metaArr[0]);  //Integer.valueOf("01")能自动处理前导0
            float buyMoney = Float.valueOf(metaArr[1]);
            dataDTO.setNum(num);
            dataDTO.setBuyMoney(buyMoney);

            dataDtos.add(dataDTO);
        }
        return dataDtos;
    }

    /**
     * 策略1：多个号子同一金额
     *
     * @param data     数据
     * @param dataList
     */
    public static void multiToOne(String data, List<String> dataList) {
        //处理 13。12。30(200) 这类格式
        data= data.replace("(", "各").replace("（","各").
                replace(")","").replace("）","");

        //1）定位金额
        String[] dataArr = data.split("各");
        Float money = extractMoneyFromStr(dataArr[1]);
        //2）定位号码
        //①如“1/3/5各20米”或“1\3\5各20米”或“1,3,5各20米”或“1.3.5各20米”或“1、3、5各20米”，先全部转换为“1 3 5各20米”格式
        dataArr[0] = dataArr[0].replace("号"," ").replace("/", " ").replace("\\", " ").
                replace(",", " ").replace("，", " ").replace("、", " ").
                replace(".", " ").replace("。", " ").
                replace("+", " ").replace("-", " ").replace("—", " ").
                replace("*"," ").replace("~"," ");
        //②最后统一对“1 3 5各20米”格式处理，统一转化成json格式[1:20,3:20,5:20]
        String[] numArr = dataArr[0].split("\\s+");
        if (hasDuplicates(numArr)) {
            log.error("******本组号码[{}]中存在重复的号码，请先检查调整！！！", dataArr[0]);
            throw new BizException(RespCodeEnum.DUPLICATE_NUM.getErrCode(),data+"存在重复的号码");
        }
        //3）纳入集合
        for (String s : numArr) {
            if (!StringUtils.hasText(s)) {  //解决：“3/4/5/各10块”以“/”结尾以及其它会产生空字符串的格式；
                continue;
            }
            dataList.add(Integer.valueOf(s) + ":" + money);
        }
    }


    /**
     * 策略2：包单双或包生肖
     *
     * @param data
     * @param dataList
     */
    public static void bag(String data, List<String> dataList) {
        List<Integer> nums;
        // 1.定位金额
        Float money = extractMoneyFromStr(data);
        // 2.类型区分处理
        //通过第二个字来判断是包单双、还是包生肖
        String key = String.valueOf(data.charAt(1));
        if (TypeConstants.animalConstant.contains(key)) {  //包生肖，如“包鼠100”、“包马羊狗15”
            for (int i = 0; i < data.length(); i++) {
                String animal = String.valueOf(data.charAt(i));
                if (TypeConstants.animalConstant.contains(animal)) {
                    // 2）定位号码
                    nums = extraNumForAnimals(animal);
                    //3）纳入集合
                    for (Integer num : nums) {
                        dataList.add(num + ":" + money);
                    }
                }
            }

        } else if (TypeConstants.oddEvenConstant.contains(key)) {  //包单双，如“包单500”
            // 2）定位号码
            nums = extraNumForOddsOrEvens(key);
            // 3）纳入集合
            for (Integer num : nums) {
                dataList.add(num + ":" + keepPoint(money / nums.size()));
            }
        } else {
            log.error("请明确包什么！！！");
            throw new BizException(RespCodeEnum.CONTENTS_FORMAT_INCORRECT);
        }
    }

    /**
     * 策略3：一个号子一个金额
     * 统一格式化：①号码与金额之间用":"隔开；②每对数据之间，使用空格" "隔开。最后统一为如"1:10 2:10 3:20..."这类格式
     *
     * @param data
     * @param dataList
     */
    public static void oneToOne(String data, List<String> dataList) {
        //支持如下格式：
        //1--10,2+++20,3///30,4**40,5—50,6——60
        //7 -- 70, 8 +++ 80,9 ///90,10** 100,11—110,12—— 120
        //13号130，14号 140，15 号150
        data = data.replace("号", "-").
                replaceAll("(\\b\\d+)\\s*[\\-—+*xX×/]+\\s*(\\d+\\b)", "$1:$2").
                /* 隔开方式 */
                        replace(",", " ").          //支持英文逗号“,”隔开，如“1/20,3/30”
                        replace("，", " ").                 //支持中文逗号“，”隔开，如“1/20，3/30”
                        replace(".", " ").                  //支持英文句号“.”隔开，如“1/20.3/30”
                        replace("。", " ").                 //支持中文句号“。”隔开，如“1/20。3/30”
                        replace("、", " ");                 //支持中文顿号“、”隔开，如“1/20、3/30”

        String[] numArr = data.split("\\s+");
        if (hasDuplicates(numArr)) {
            log.error("******本组号码[{}]中存在重复的号码，请先检查调整！！！", numArr);
            throw new BizException(RespCodeEnum.DUPLICATE_NUM);
        }
        for (String s : numArr) {
            dataList.add(s);
        }
    }


    /**
     * 从字符串中解析生肖对应的号码
     *
     * @param animal 生肖
     * @return
     */
    public static List<Integer> extraNumForAnimals(String animal) {
        if (animal.length() != 1) {
            log.error("******生肖的字数只能为1，如“鼠”，不能写成“老鼠”");
            throw new BizException(RespCodeEnum.CONTENTS_FORMAT_INCORRECT);
        }

        List<Integer> nums = DataInitializer.getAnimalMap().get(animal);
        log.info("包" + animal + "共有号码为：" + nums);
        return nums;
    }


    /**
     * 从字符串中解析单双对应的号码
     *
     * @param key 单、双
     * @return
     */
    public static List<Integer> extraNumForOddsOrEvens(String key) {
        if (key.length() != 1) {
            log.error("******请明确包双还是包单");
            throw new BizException(RespCodeEnum.CONTENTS_FORMAT_INCORRECT);
        }

        List<Integer> nums = DataInitializer.getOddsEvensMap().get(key);
        log.info("包" + key + "共有号码为：" + nums);

        return nums;
    }


    /**
     * 从字符串中抽离出金额
     *
     * @param str
     * @return
     */
    public static Float extractMoneyFromStr(String str) {
        String regEx = "[^0-9]";
        Pattern p = Pattern.compile(regEx);
        Matcher m = p.matcher(str);
        String money = m.replaceAll("").trim();
        if (!StringUtils.hasText(money)) {
            log.error("******对应项未输入金额！");
            throw new BizException(RespCodeEnum.CONTENTS_FORMAT_INCORRECT);
        }

        return Float.valueOf(money);
    }

    /**
     * 保留2位小数
     *
     * @param money 金额
     * @return
     */
    public static Float keepPoint(Float money) {
        return ((float) Math.round(money * 100)) / 100;
    }

    /**
     * 判断该组号码中是否有重复的号码
     * 还需考虑如2、02这类
     *
     * @param arr
     * @return
     */
    public static boolean hasDuplicates(String[] arr) {
        return Arrays.stream(arr).distinct().count() != arr.length;
        //return Arrays.stream(arr).map(i -> Integer.valueOf(i)).distinct().count() != arr.length;
    }

    /**
     * 计算初版数据
     *
     * @param dataDTO     原始数据
     * @param eatMaxValue 每个号子消化的最大值
     */
    public static void calculateInitialValue(DataDTO dataDTO, Integer eatMaxValue) {
        if (dataDTO.getBuyMoney() <= eatMaxValue) {
            dataDTO.setExcludeMoney(0);
            dataDTO.setEatMoney(dataDTO.getBuyMoney());
        } else {
            dataDTO.setExcludeMoney(dataDTO.getBuyMoney() - eatMaxValue);
            dataDTO.setEatMoney(eatMaxValue);
        }
    }

    /**
     * 将形如"1:20 2:20 3:10"这类字符串转换成Map
     * 如果该组数据中存在相同的号码，如"1-20 2-20 1-10"，将会对相同号码进行金额累计
     *
     * @param str
     * @return
     */
    public static Map<Integer, Integer> jsonstrToMap(String str) {
        Map<Integer, Integer> map = new HashMap<>();
        String[] strArr = str.split("\\s+");
        for (String s : strArr) {
            String[] res = s.split(":");
            if (map.get(Integer.valueOf(res[0])) == null) {
                map.put(Integer.valueOf(res[0]), Integer.valueOf(res[1]));
            } else {
                log.info("******该组{}数据中，存在至少两个相同的号码[{}]", strArr, Integer.valueOf(res[0]));
                map.put(Integer.valueOf(res[0]), map.get(Integer.valueOf(res[0])) + Integer.valueOf(res[1]));
            }

        }
        return map;
    }


}
